#include "SpiInitHelper.h"

#include "SimpleCompletion.h"

Spi_Transport_Def spi3_obj;

//SPIx Config
void App_SPIxCfg(void) {
  stc_spi_init_t stcSpiInit;
  stc_spi_delay_t stcSpiDelay;

  /* Enable SPI3 clock */
  FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_SPI3, ENABLE);
  /************************* Configure SPI3***************************/
  SPI_StructInit(&stcSpiInit);
  stcSpiInit.u32WireMode = SPI_4_WIRE;
  stcSpiInit.u32TransMode = SPI_FULL_DUPLEX;
  stcSpiInit.u32MasterSlave = SPI_MASTER;
  stcSpiInit.u32Parity = SPI_PARITY_INVD;
  stcSpiInit.u32SpiMode = SPI_MD_0;
  stcSpiInit.u32BaudRatePrescaler = SPI_BR_CLK_DIV2;
  stcSpiInit.u32DataBits = SPI_DATA_SIZE_8BIT;
  stcSpiInit.u32FirstBit = SPI_FIRST_MSB;
  stcSpiInit.u32SuspendMode = SPI_COM_SUSP_FUNC_OFF;
  stcSpiInit.u32FrameLevel = SPI_1_FRAME;
  (void) SPI_Init(CM_SPI3, &stcSpiInit);

  SPI_DelayStructInit(&stcSpiDelay);
  stcSpiDelay.u32IntervalDelay = SPI_INTERVAL_TIME_2SCK;
  stcSpiDelay.u32ReleaseDelay = SPI_RELEASE_TIME_1SCK;
  stcSpiDelay.u32SetupDelay = SPI_SETUP_TIME_4SCK;
  (void) SPI_DelayTimeConfig(CM_SPI3, &stcSpiDelay);

//  /* SPI loopback function configuration */
//  SPI_LoopbackModeConfig(CM_SPI3, SPI_LOOPBACK_INVD);
//  /* SPI parity check error self diagnosis configuration */
//  SPI_ParityCheckCmd(CM_SPI3, DISABLE);
//  /* SPI valid SS signal configuration */
//  SPI_SSPinSelect(CM_SPI3, SPI_PIN_SS0);
//  /* SPI SS signal valid level configuration */
//  SPI_SSValidLevelConfig(CM_SPI3, SPI_PIN_SS0, DISABLE);
  /* Enable interrupt function*/
  SPI_IntCmd(CM_SPI3,  SPI_INT_ERR, ENABLE);
  /* Enable SPI3 */
  //SPI_Cmd(CM_SPI3, ENABLE);
}

// spi3 接收中断
void INT_SRC_DMA2_TC3_IrqCallback(void) {
  DMA_ClearTransCompleteStatus(CM_DMA2, DMA_CH3);
	DMA_ChCmd(CM_DMA2, DMA_CH2, DISABLE);
  DMA_ChCmd(CM_DMA2, DMA_CH3, DISABLE);
  completion_done(&(spi3_obj.spi_transport_sem));
}// spi3 接收中断

// spi3 空闲中断
void INT_SRC_SPI3_SPII_IrqCallback(void) {
	SPI_ClearStatus(CM_SPI3, SPI_FLAG_IDLE);
	SPI_IntCmd(CM_SPI3,  SPI_INT_IDLE, DISABLE);
	DMA_ClearTransCompleteStatus(CM_DMA2, DMA_CH3);
	DMA_ChCmd(CM_DMA2, DMA_CH2, DISABLE);
  DMA_ChCmd(CM_DMA2, DMA_CH3, DISABLE);
  completion_done(&(spi3_obj.spi_transport_sem));
} // spi3 空闲中断

rt_err_t Init_Spi3_Obj(void) {
  rt_mutex_init(&(spi3_obj.spi3_lock), "spi3 port mutex", RT_IPC_FLAG_PRIO);
  rt_sem_init(&(spi3_obj.spi_transport_sem), "spi3 transport sem", 0, RT_IPC_FLAG_PRIO);
  STATU_SET(spi3_obj.spi_status, SPI_INITED);
  spi3_obj.spi_tx_buf = spi3_tx_buf;
  spi3_obj.spi_rx_buf = spi3_rx_buf;
  spi3_obj.cm_dma_tx = CM_DMA2;
  spi3_obj.dma_ch_tx = DMA_CH2;
	spi3_obj.cm_dma_rx = CM_DMA2;
  spi3_obj.dma_ch_rx = DMA_CH3;
	spi3_obj.spi_cm = CM_SPI3;
	
	return RT_EOK;
}

rt_err_t Spi_Start_Wait(Spi_Transport_Def *obj) {
  DMA_SetSrcAddr(obj->cm_dma_tx, obj->dma_ch_tx, (uint32_t) (obj->spi_tx_buf));
  DMA_SetTransCount(obj->cm_dma_tx, obj->dma_ch_tx, obj->spi_tx_size + obj->spi_rx_size);
  DMA_SetDestAddr(obj->cm_dma_rx, obj->dma_ch_rx, (uint32_t) (obj->spi_rx_buf));
  DMA_SetTransCount(obj->cm_dma_rx, obj->dma_ch_rx, obj->spi_tx_size + obj->spi_rx_size);
  /* Enable DMA channel */
  DMA_ChCmd(obj->cm_dma_tx, obj->dma_ch_tx, ENABLE);
  DMA_ChCmd(obj->cm_dma_rx, obj->dma_ch_rx, ENABLE);
	//SPI_IntCmd(CM_SPI3,  SPI_INT_IDLE, ENABLE);
	SPI_Cmd(CM_SPI3, ENABLE);
	rt_err_t res = completion_wait(&(obj->spi_transport_sem), 500);

	SPI_Cmd(CM_SPI3, DISABLE);
	
	return res;
}

rt_err_t Spi_Set_Band(Spi_Transport_Def *obj, uint32_t u32BaudRatePrescaler){
	LL_PERIPH_WE(LL_PERIPH_PWC_CLK_RMU);
	uint32_t reg = READ_REG32(obj->spi_cm->CFG2);
	STATU_SET(reg, u32BaudRatePrescaler);
	WRITE_REG32(obj->spi_cm->CFG2, reg);
	LL_PERIPH_WP(LL_PERIPH_PWC_CLK_RMU);
	return RT_EOK;
}
